
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "dna_json.h"
#include "dna_errno.h"
#include "dna_libc.h"
#include "dna_utils.h"


#define tc_log(_fmt_, ...) \
        printf("[TC][%s:%d][%s] "_fmt_"\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define tc_log_err(_fmt_, ...) \
        printf("[TC][ERR][%s:%d][%s] "_fmt_"\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)


unsigned long dna_system_ticks(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    // printf("%d %d\n", tv.tv_sec, tv.tv_usec);
    return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
}

static int test_makeup_msg(unsigned char *output, int maxsize)
{
    snprintf(output, maxsize, "{\"mtag\":\"whitelist\"}");
    return strlen(output);
}

static int test_parse_msg(unsigned char *input, int ilen)
{
#define PD_JSON_SUBOBJ_PARSE_BUFFSIZE   256
    dna_json_object_t jobj, json_sub[3];
    dna_json_val_list_t para_list[3];
    char data[3][PD_JSON_SUBOBJ_PARSE_BUFFSIZE], valstr[64];
    char *pdata[3];
    int val, i, j, n;

    dna_json_object_init(&jobj, input);
    
    dna_json_get_val_int(&jobj, "status", &val);
    if (val != 0) {
        tc_log_err("get status err %d", val);
        return -DNA_FAIL;
    }

    pdata[0] = dna_json_get_array_subobj(&jobj, "data", data[0], PD_JSON_SUBOBJ_PARSE_BUFFSIZE, &para_list[0]);
    tc_log("subobj data count %d", para_list[0].count);

    for (i = 0; i < para_list[0].count; ++i) {
        dna_json_object_init(&json_sub[0], pdata[0] + para_list[0].pos[i]);

        dna_json_get_val_int(&json_sub[0], "devversion", &val);
        tc_log("get devversion %d", val);

        pdata[1] = dna_json_get_array_subobj(&json_sub[0], "dataList", data[1], PD_JSON_SUBOBJ_PARSE_BUFFSIZE, &para_list[1]);
        tc_log("subobj dataList count %d", para_list[1].count);

        for (j = 0; j < para_list[1].count; ++j) {
            dna_json_object_init(&json_sub[1], pdata[1] + para_list[1].pos[j]);

            /* mtag */
            dna_json_get_val_str(&json_sub[1], "mtag", valstr, sizeof(valstr));
            tc_log("get mtag %s", valstr);

            if (strcmp(valstr, "dev_whitelist")) {
                tc_log_err("get mtag err %d", valstr);
                break;
            }

            /* updatetime */
            dna_json_get_val_str(&json_sub[1], "updatetime", valstr, sizeof(valstr));
            tc_log("get updatetime %s", valstr);

            /* data */
            dna_json_get_composite_object(&json_sub[1], "data");

            pdata[2] = dna_json_get_array_subobj(&json_sub[1], "whitelist", data[2], PD_JSON_SUBOBJ_PARSE_BUFFSIZE, &para_list[2]);
            tc_log("subobj whitelist count %d", para_list[2].count);

            for (n = 0; n < para_list[2].count; ++n) {
                dna_json_object_init(&json_sub[2], pdata[2] + para_list[2].pos[n]);

                /* did */
                dna_json_get_val_str(&json_sub[2], "did", valstr, sizeof(valstr));
                tc_log("get did %s", valstr);

                /* pid */
                dna_json_get_val_str(&json_sub[2], "pid", valstr, sizeof(valstr));
                tc_log("get pid %s", valstr);
            }

            dna_json_release_composite_object(&json_sub[2]);
        }
    }
    return DNA_SUCCESS;
}

static void test(void)
{
    const char *teststr = "{\"status\":0,\"msg\":\"\",\"total\":0,\"count\":0,\"context\":\"\",\"data\":[{\"did\":\"00000000000000000000780f77e693cb\",\"devversion\":0,\"dataList\":[{\"mtag\":\"dev_whitelist\",\"data\":{ \"whitelist\":[{\"did\":\"xxxxxxxx\", \"pid\":\"\"},{\"did\":\"xxxxxxxx\", \"pid\":\"\"}]},\"updatetime\":\"xxx\"}]}]}";

    bl_pd_init();

    bl_pd_request(10022, 10024, test_makeup_msg, test_parse_msg);
    bl_pd_request(10022, 10023, test_makeup_msg, test_parse_msg);

#if 0
    int cnt = 0;
    while (cnt++ < 10 * 60) {
        bl_pd_polling();
        sleep(1);
        tc_log("running...");
    }
#endif

    bl_pd_handler(teststr, strlen(teststr));
}

void dna_hexdump(const void *data, size_t size, const char *str, ...)
{
    char t_str[128];
    char hexByte[4];
    char hexLine[50];
    char charByte[2];
    char charLine[18];
    unsigned int i;

    va_list args;
    va_start(args, str);
    int len = vsnprintf(t_str, sizeof(t_str), str, args);
    va_end(args);
    printf("%.*s\r\n", len, t_str);

    for (i = 0; i < size; i++) {
        if (i % 16 == 0) {
            hexLine[0] = 0;
            charLine[0] = 0;
        }
        if (i % 16 == 8) {
            strcat(hexLine, " ");
            strcat(charLine, " ");
        }
        dna_snprintf(hexByte, sizeof(hexByte), " %02x", ((unsigned char *) data)[i]);
        strcat(hexLine, hexByte);
        if (((unsigned char *) data)[i] < 32 || ((unsigned char *) data)[i] > 126) {
            strcat(charLine, ".");
        } else {
            dna_snprintf(charByte, sizeof(charByte), "%c", ((unsigned char *) data)[i]);
            strcat(charLine, charByte);
        }
        if (i % 16 == 15 || i == size - 1) {
            printf("%04x:%-49s  %s\r\n", i & ~15, hexLine, charLine);
        }
    }
}

static void test2(void)
{
    unsigned char valstr[64], mac[6], adding = !0, *addr;
    unsigned int devtype;

    addr = (unsigned char *)&devtype;
    memset(addr, 0x5a, 4);

    /* did */
    strcpy(valstr, "00000000000000000000c8f74281f7ef");
    tc_log("get did %s", valstr);

    if (strlen(valstr) == 32) {
        sscanf(valstr, "00000000000000000000%02x%02x%02x%02x%02x%02x", \
               &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
        tc_log("whitelist mac %02x:%02x:%02x:%02x:%02x:%02x", \
                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    } else {
        adding = 0;
    }

    /* pid */
    strcpy(valstr, "00000000000000000000000068751234");
    tc_log("get pid %s", valstr);

    dna_hexdump(mac, 6, "whitelist mac");

    tc_log("&devtype %p mac %p valstr %p", &devtype, mac, valstr);

    if (strlen(valstr) == 32) {
        unsigned char *pbyte = (unsigned char *)&devtype;
        tc_log("pbyte %p pbyte + 1 %p pbyte + 2 %p pbyte + 3 %p", \
                pbyte, pbyte + 1, pbyte + 2, pbyte + 3);
        sscanf(valstr, "000000000000000000000000%02x%02x%02x%02x", \
               pbyte, pbyte + 1, pbyte + 2, pbyte + 3);

        dna_hexdump(mac, 6, "whitelist mac");
        dna_hexdump(&devtype, 20, "devtype");
    } else {
        /* add this device even if pid is empty */
        devtype = 0;
    }

    dna_hexdump(mac, 6, "whitelist mac");
    dna_hexdump(&devtype, sizeof(unsigned int), "devtype");
}

static void mock_test(const char *input)
{
    tc_log("%s", input);
}

static void test3(const char *mtag)
{
    struct mtag_hdl {
        char *mtag;
        void (*handler)(const char *input);
    } mtag_hdl_var[] = {
        {"dev_whitelist", mock_test},
        {"fcbg_cfg",      mock_test},
        NULL,
    };
    struct mtag_hdl *pwalk = mtag_hdl_var;

    tc_log("mtag: %s", mtag);

    while (pwalk->mtag != NULL) {
        tc_log("pwalk %p mtag %s", pwalk, pwalk->mtag);
        if (!dna_strcmp(pwalk->mtag, mtag))
            (*(pwalk->handler))(pwalk->mtag);

        pwalk++;
    }

    return DNA_SUCCESS;
}

static void test4(void)
{
    const char base64[] = "soAmABEGBQYFCwoGBQsKCwYGBgUGBgoLBgYKBgUGBQYFBgYLBQUGBQUGAAA=";
    unsigned char output[256];
    int olen = sizeof(output);

    int ret = dna_base64decode(base64, strlen(base64), output, &olen);
    tc_log("base64 decode olen %d ret %d", olen, ret);
    dna_hexdump(output, olen, "base64 decode");
}

int main(int argc, char const *argv[])
{
    tc_log("********************");
    tc_log("new start @ %s %s", __DATE__, __TIME__);
    tc_log("********************");

    tc_log("sizeof(unsigned int) %d", sizeof(unsigned int));

    test4(); 

    tc_log("exit");
    return 0;
}

